package fr.asip.cps3.exemple.modele.objets;

import iaik.pkcs.pkcs11.wrapper.CK_SESSION_INFO;
import iaik.pkcs.pkcs11.wrapper.PKCS11;
import iaik.pkcs.pkcs11.wrapper.PKCS11Constants;
import iaik.pkcs.pkcs11.wrapper.PKCS11Exception;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.log4j.Logger;

import fr.asip.cps3.exemple.modele.exceptions.ExceptionObjet;
import fr.asip.cps3.exemple.modele.exceptions.ExceptionProgrammeExemple;
import fr.asip.cps3.exemple.modele.traitements.util.TraitementsUtil;

/**
 * Classe modélisant une session
 *
 */
public class Session {

	/**
	 * Le loggeur
	 */
	 private static Logger log = Logger.getLogger(Session.class);
	
	/**
	 * Identifiant de la Session
	 */
	private long idSession;
	
	/**
	 * Numéro de série du token sur lequel la session est établie
	 */
	private String idToken;
	
	/**
	 * Informations sur la session
	 */
	CK_SESSION_INFO info;
	
	/**
	 * Date d'ouverture
	 */
	Date dateOuverture;
	
	/**
	 * Constructeur
	 * @param librairie Librairie PKCS#11 à utiliser
	 * @param idToken Identifiant de la carte
	 * @param idSession Identifiant de la session
	 * @throws ExceptionObjet 
	 */
	public Session(PKCS11 librairie, String idToken, long idSession) throws ExceptionObjet {
		
		this.idToken = idToken;
		this.idSession = idSession;
		// on stocke la date d'ouverture de la session
		this.dateOuverture = new Date();
		
		chargeInfo(librairie);
		
	}

	/**
	 * (Re)chargement explicite des informations de la session
	 * @param librairie Librairie PKCS#11 à utiliser
	 * @throws ExceptionObjet
	 */
	public void chargeInfo(PKCS11 librairie) throws ExceptionObjet {

		if(librairie != null) {
			
			try {
				
				info = librairie.C_GetSessionInfo(idSession);
			
			} catch (PKCS11Exception e) {
			
				// Si une erreur PKCS#11 est rencontrée on log et on lève l'exception
				log.error("Une erreur est survenue lors de la recuperation des informations de la session : "+TraitementsUtil.retranscritCodeRetour(e.getErrorCode()));
				throw new ExceptionObjet(ExceptionProgrammeExemple.TYPE_OBJET_SESSION, "Une erreur est survenue lors de la récuperation des informations de la session",e);
			
			}
		} else {
			
			// Si la librairie est nulle il est impossible de récupérer les informations de la session
			log.error("La librairie est nulle");
			throw new ExceptionObjet(ExceptionProgrammeExemple.TYPE_OBJET_SESSION, "La librairie est nulle");
			
		}
		
	
	}
	
	/**
	 * Renvoie le libellé du session
	 * @return Libellé du session
	 */
	public String getLibelle() {
		
		String libelle = "Session "+idSession;
		
		if(info != null) {
			
			libelle += " (";
			
			long state = info.state;
			if(state == PKCS11Constants.CKS_RO_PUBLIC_SESSION)
				libelle += "RO public";
			else if(state == PKCS11Constants.CKS_RO_USER_FUNCTIONS)
				libelle += "RO utilisateur";
			else if(state == PKCS11Constants.CKS_RW_PUBLIC_SESSION)
				libelle += "RW public";
			else if(state == PKCS11Constants.CKS_RW_SO_FUNCTIONS)
				libelle += "RW SO";
			else if(state == PKCS11Constants.CKS_RW_USER_FUNCTIONS)
				libelle += "RW utilisateur";
			
			try {
				
				libelle+="/Slot "+Long.toString(getIdSlot());
				
			} catch (ExceptionObjet e) {
				
				// On ne fait rien, car on peut afficher un libelle sans l'information sur le slot
				
			}
			
			SimpleDateFormat df = new SimpleDateFormat( "yyyyMMdd hh:mm:ss" );
			libelle+="/"+df.format(dateOuverture);

			libelle += ")";		

		}
		
		return libelle;
	}

	/**
	 * Accesseur
	 * @return Identifiant de la session
	 */
	public long getIdSession() {
		return idSession;
	}


	
	/**
	 * Accesseur
	 * @return Numéro de série du token sur lequel la session est établie
	 */
	public String getIdToken() {
		return idToken;
	}

	/**
	 * Identifiant du slot hébergeant le token
	 * @return Identifiant du slot hébergeant le token
	 * @throws ExceptionObjet 
	 */
	public long getIdSlot() throws ExceptionObjet{
		
		if(info != null)
			return info.slotID;
		else {
			
			log.error("Les informations de la session sont nulles, l'identifiant du slot est indisponible");
			throw new ExceptionObjet(ExceptionProgrammeExemple.TYPE_OBJET_SESSION, "L'identifiant du slot est indisponible");
			
		}
		
	}

	/**
	 * La session est-elle en lecture seule non loguée?
	 * @return Réponse
	 * @throws ExceptionObjet 
	 */
	public boolean isSessionLectureSeuleNonLoguee() throws ExceptionObjet {
		
		if(info != null) {
			
			long state = info.state;
			if((state & PKCS11Constants.CKS_RO_PUBLIC_SESSION)!=0)
				return true;
			return false;
			
		} else {
			
			log.error("Les informations de la session sont nulles, l'information sur la session est indisponible");
			throw new ExceptionObjet(ExceptionProgrammeExemple.TYPE_OBJET_SESSION, "L'information sur la session est indisponible");
			
		}
		
	}

	/**
	 * La session est-elle en lecture seule loguée utilisateur?
	 * @return Réponse
	 * @throws ExceptionObjet 
	 */
	public boolean isSessionLectureSeuleLogueeUtilisateur() throws ExceptionObjet {
		
		if(info != null) {
			
			long state = info.state;
			if((state & PKCS11Constants.CKS_RO_USER_FUNCTIONS)!=0)
				return true;
			return false;
			
		} else {
			
			log.error("Les informations de la session sont nulles, l'information sur la session est indisponible");
			throw new ExceptionObjet(ExceptionProgrammeExemple.TYPE_OBJET_SESSION, "L'information sur la session est indisponible");
			
		}		
	}
	
	/**
	 * La session est-elle en lecture ecriture loguée SO?
	 * @return Réponse
	 * @throws ExceptionObjet 
	 */
	public boolean isSessionLectureEcritureLogueeSO() throws ExceptionObjet {
		
		if(info != null) {
			long state = info.state;
			if((state & PKCS11Constants.CKS_RW_SO_FUNCTIONS)!=0)
				return true;
			return false;
			
		} else {
			
			log.error("Les informations de la session sont nulles, l'information sur la session est indisponible");
			throw new ExceptionObjet(ExceptionProgrammeExemple.TYPE_OBJET_SESSION, "L'information sur la session est indisponible");
			
		}
		
	}
	
	/**
	 * La session est-elle en lecture ecriture loguée utilisateur?
	 * @return Réponse
	 * @throws ExceptionObjet 
	 */
	public boolean isSessionLectureEcritureLogueeUtilisateur() throws ExceptionObjet {
		
		if(info != null) {
			long state = info.state;
			if((state & PKCS11Constants.CKS_RW_USER_FUNCTIONS)!=0)
				return true;
			return false;
			
		} else {
			
			log.error("Les informations de la session sont nulles, l'information sur la session est indisponible");
			throw new ExceptionObjet(ExceptionProgrammeExemple.TYPE_OBJET_SESSION, "L'information sur la session est indisponible");
			
		}
		

	}
	
	/**
	 * Renvoie l'état de la session
	 * @return L'état de la session
	 * @throws ExceptionObjet 
	 */
	public long getEtatSession() throws ExceptionObjet {
		if(info != null)
			return info.state;
		else {
		
			log.error("Les informations de la session sont nulles, l'information sur l'état de la session est indisponible");
			throw new ExceptionObjet(ExceptionProgrammeExemple.TYPE_OBJET_SESSION, "L'information sur l'état de la session est indisponible");
		
		}
	}	
	
	@Override
	public String toString() {
		return getLibelle();
	}
	
}
